#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

#define SERVER_PORT 8888
#define BUF_SIZE 1024
// 工作进程
void handle_client(int client_socket) {
    // 在子进程中，创建一个无限循环来处理客户端发送的命令
    char buffer[BUF_SIZE];
    while (1) {
        // 1. 读取客户端发送的命令
        // 2. 根据命令的类型执行相应的操作
        // 3. 将结果发送回客户端
        // 4. 当收到客户端发送的quit命令时，子进程退出循环并关闭连接（这个直接在客户端解决了）
        memset(buffer, 0, sizeof(buffer)); // 清零
        int n = read(client_socket, buffer, BUF_SIZE);
        if (n <= 0) {
            break;
        }
        buffer[n] = '\0';

        /* if (strncmp(buffer, "quit", 4) == 0) {
            // strncmp 函数比较 buffer 和字符串 "quit" 的前4个字符，如果相同，则返回0
            break;
        } else */
        if (strncmp(buffer, "pwd", 3) == 0) {
            getcwd(buffer, BUF_SIZE);
            // getcwd 函数获取当前工作目录的路径（getcwd 将路径存储在 buffer 中，最多存储 BUF_SIZE 个字符）
            write(client_socket, buffer, strlen(buffer));
            // write 函数将 buffer 中的路径（当前工作目录）发送回客户端，发送的数据长度为 strlen(buffer)，即路径字符串的长度
        } else if (strncmp(buffer, "cd ", 3) == 0) {
            // chdir 函数来改变当前工作目录，执行成功时返回0，否则返回-1
            int result = chdir(buffer + 3);
            if (result == 0) {
                write(client_socket, "Directory changed\n", 18);
            } else {
                write(client_socket, "Failed to change directory\n", 27);
            }
        } else if (strncmp(buffer, "ls", 2) == 0) {
            FILE *fp = popen("ls", "r");
            if (fp) {
                while (fgets(buffer, BUF_SIZE, fp) != NULL) {
                    write(client_socket, buffer, strlen(buffer));
                }
                pclose(fp);
            }
        } else {
            write(client_socket, "Unknown command\n", 16);
        }
    }
    close(client_socket);
}

int main() {
    // 创建TCP套接字
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        perror("socket creation failed");
        exit(1);
    }

    // 设置服务器地址结构
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);

    // 设置重用套接字选项 
    int opt_val = 1;
    if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val)) == -1) {
        perror("setsockopt");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    // 绑定套接字到指定的IP地址和端口
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        exit(1);
    }

    // 监听套接字，准备接收客户端连接
    if (listen(server_socket, 5) < 0) {
        perror("listen failed");
        exit(1);
    }

    printf("Server is listening on port %d...\n", SERVER_PORT);

    // 服务器主循环，等待并处理客户端连接
    // IO 进程
    while (1) {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);

        if (client_socket < 0) {
            perror("accept failed");
            continue;
        }

        // 创建子进程来处理客户端请求
        pid_t pid = fork();
        if (pid < 0) {
            perror("fork failed");
            close(client_socket);
            continue;
        } else if (pid == 0) { // 子进程
            close(server_socket);
            handle_client(client_socket);
            close(client_socket);
            exit(0);
        } else { // 父进程
            close(client_socket);
            waitpid(-1, NULL, WNOHANG); // 避免僵尸进程
        }
    }

    return 0;
}
